////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 CORE Solutions Limited
// All rights reserved.
// PROPRIETARY AND CONFIDENTIAL INFORMATION.
// Use is subject to license terms.
//
// FUNCTION ID      :   CopyUtil
// AUTHOR           :
// DATE CREATE      :
// DESCRIPTION      :
//                  :
//                  :
//                  :
//
// MODIFICATION HISTORY:
// DATE         AUTHOR          VERSION NO.         COMMENT
// -----------  --------------  ------------------  -------------------
// 2006/06/05   Cyris Liang     1.0                 BugZilla #6041
// 2006/06/08   Ric Yik         1.0                 BugZilla #6166
//
//
////////////////////////////////////////////////////////////////////////////////

package com.erp.framework.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;

import org.apache.commons.beanutils.PropertyUtils;

import com.erp.framework.SimpleConstants;
import com.erp.framework.model.vo.ChildList;
import com.erp.framework.types.CustomBigDecimal;
import com.erp.framework.types.CustomBigInteger;
import com.erp.framework.types.CustomSqlDate;
import com.erp.framework.types.CustomTimestamp;
import com.erp.framework.types.CustomUtilDate;
import com.erp.framework.util.logger.Logger;

public class CopyUtil implements SimpleConstants {

    public static void cpNconv(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {

        if (dest == null)
            throw new IllegalArgumentException("No destination bean specified");
        if (orig == null)
            throw new IllegalArgumentException("No origin bean specified");
        PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(orig);
        for (int i = 0; i < origDescriptors.length; i++) {
            String name = origDescriptors[i].getName();
            Class oriType = PropertyUtils.getPropertyType(orig, name);
            try {
                PropertyDescriptor origPd = PropertyUtils.getPropertyDescriptor(orig, name);
                PropertyDescriptor destPd = PropertyUtils.getPropertyDescriptor(dest, name);
                if (destPd != null && destPd.getWriteMethod() != null && origPd != null && origPd.getReadMethod() != null) {
                    Class type = PropertyUtils.getPropertyType(dest, name);
                    if (oriType == String.class) {
                        String value = (String) PropertyUtils.getSimpleProperty(orig, name);
                        if (!type.isPrimitive()) {
                            if (type == Integer.class) {
                                Integer inValue = CommonUtil.strToInteger(value);
                                PropertyUtils.setProperty(dest, name, inValue);
                            } else if (type == BigInteger.class) {
                                BigInteger inValue = CommonUtil.strToBigInteger(value);
                                PropertyUtils.setProperty(dest, name, inValue);
                            } else if (type == CustomBigInteger.class) {
                                CustomBigInteger bd = CommonUtil.isEmpty(value) ? null : CustomBigInteger.customize(CommonUtil
                                        .strToBigInteger(value));
                                PropertyUtils.setSimpleProperty(dest, name, bd);
                            } else if (type == BigDecimal.class) {
                                BigDecimal bd = CommonUtil.isEmpty(value) ? null : CommonUtil.strToBigDecimal(value);
                                PropertyUtils.setSimpleProperty(dest, name, bd);
                            } else if (type == CustomBigDecimal.class) {
                                CustomBigDecimal bd = CommonUtil.isEmpty(value) ? null : CustomBigDecimal.customize(CommonUtil
                                        .strToBigDecimal(value));
                                PropertyUtils.setSimpleProperty(dest, name, bd);
                            } else if (type == java.util.Date.class) {
                                java.util.Date inValue = null;
//                                if (value != null && value.length() == 8) {
//                                    inValue = CommonUtil.stringToDate(value);
//                                    PropertyUtils.setProperty(dest, name, inValue);
//                                } else if (value != null && value.length() == 10) {
//                                    inValue = CommonUtil.stringWithSlashToDate(value);
//                                    PropertyUtils.setProperty(dest, name, inValue);
//                                } else {
                                    inValue = CommonUtil.stringToDate(value);
                                    PropertyUtils.setProperty(dest, name, inValue);
//                                }
                            } else if (type == java.sql.Date.class) {
                               java.util.Date inValue = CommonUtil.stringToDate(value);
                                //if (value != null && value.length() == 8) {
                                    inValue = CommonUtil.stringToDate(value);
                                    java.sql.Date dateValue = inValue == null ? null : new java.sql.Date(inValue.getTime());
                                    PropertyUtils.setProperty(dest, name, dateValue);
                               // }
                                    /*else if (value != null && value.length() == 10) {
                                    inValue = CommonUtil.stringWithSlashToDate(value);
                                    java.sql.Date dateValue = inValue == null ? null : new java.sql.Date(inValue.getTime());
                                    PropertyUtils.setProperty(dest, name, dateValue);
                                } else {
                                    inValue = CommonUtil.stringToDate(value);
                                    PropertyUtils.setProperty(dest, name, inValue);
                                }*/
                            } else if (type == java.sql.Timestamp.class) {
                                Timestamp inValue = null;
                                if ((name.startsWith(SimpleConstants.CREATE_DATE_FIELD_NAME))
                                        || (name.startsWith(SimpleConstants.UPDATE_DATE_FIELD_NAME))) {
                                    inValue = CommonUtil.stringToTimestamp(value);
                                } else {
                                    inValue = CommonUtil.stringToTimestamp(value, CommonUtil.INPUT_DATETIME_FORMAT);
                                }
                                PropertyUtils.setProperty(dest, name, inValue);
                            } else if (type == CustomUtilDate.class) {
                                CustomUtilDate inValue = CustomUtilDate.customize(CommonUtil.stringToDate(value,
                                        CommonUtil.INPUT_DATE_FORMAT));
                                PropertyUtils.setProperty(dest, name, inValue);
                            } else if (type == CustomSqlDate.class) {
                                CustomSqlDate inValue = CustomSqlDate.customize(CommonUtil.stringToDate(value,
                                        CommonUtil.INPUT_DATE_FORMAT));
                                PropertyUtils.setProperty(dest, name, inValue);
                            } else if (type == CustomTimestamp.class) {
                                CustomTimestamp inValue = CustomTimestamp.customize(CommonUtil.stringToTimestamp(value,
                                        CommonUtil.INPUT_DATETIME_FORMAT));
                                PropertyUtils.setProperty(dest, name, inValue);
                            } else if (type == String.class) {
                                // Poor Practice perhaps, setting everything to
                                // null;
                                if (value != null && value.trim().equals(""))
                                    value = null;
//                                if ((name.toUpperCase().indexOf(SimpleConstants.PARTIAL_SIZ_FIELD_NAME.toUpperCase()) != -1)
//                                        || (name.toUpperCase().indexOf(SimpleConstants.PARTIAL_COLOR_FIELD_NAME.toUpperCase()) != -1)) {
//                                    if (value == null || value.trim().equals("")) {
//                                        value = ""; //SimpleConstants.DB_NIL;
//                                    }
//                                }
                                PropertyUtils.setSimpleProperty(dest, name, value);
                            }
                        } else {
                            if (type == int.class) {
                                Integer intValue = CommonUtil.strToInteger(value);
                                PropertyUtils.setProperty(dest, name, intValue);
                            }
                        }
                    } else if (oriType == type) {
                        Object oriValue = PropertyUtils.getSimpleProperty(orig, name);
                        PropertyUtils.setSimpleProperty(dest, name, oriValue);
                    }
                }
            } catch (NoSuchMethodException e) {
                // Kind of ugly coding here
            } catch (Exception e) {
                Logger.logExceptions(e);
            }
        }
    }

    public static void convToStrObj(Object destObj, Object oriObj) throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {

        if (destObj == null)
            throw new IllegalArgumentException("No destObj bean specified");
        if (oriObj == null)
            throw new IllegalArgumentException("No oriObj bean specified");
        CommonUtil CommonUtil = new CommonUtil();
        PropertyDescriptor destProps[] = PropertyUtils.getPropertyDescriptors(destObj);
        for (int i = 0; i < destProps.length; i++) {
            String name = destProps[i].getName();
            if (PropertyUtils.getPropertyDescriptor(oriObj, name) != null && destProps[i].getPropertyType() == String.class && destProps[i].getWriteMethod() != null) {
                try {
                    PropertyDescriptor oriProp = PropertyUtils.getPropertyDescriptor(oriObj, name);
                    Class oriType = oriProp.getPropertyType();
                    Object oriValue = PropertyUtils.getSimpleProperty(oriObj, name);
                    String strValue = null;
                    if (oriValue != null) {
                        if (oriType == String.class) {
                            strValue = (String) oriValue;
                        } else if (oriType == BigDecimal.class) {
                            strValue = CommonUtil.bigDecimalToStr((BigDecimal) PropertyUtils.getSimpleProperty(oriObj, name));
                        } else if (oriType == BigInteger.class) {
                            strValue = CommonUtil.bigIntegerToStr((BigInteger) PropertyUtils.getSimpleProperty(oriObj, name));
                        } else if (oriType == Integer.class) {
                            strValue = CommonUtil.integerToStr((Integer) PropertyUtils.getSimpleProperty(oriObj, name));
                        } else if (oriType == CustomBigInteger.class) {
                            strValue = CommonUtil.bigIntegerToStr((CustomBigInteger) PropertyUtils
                                    .getSimpleProperty(oriObj, name));
                        } else if (oriType == CustomBigDecimal.class) {
                            strValue = CommonUtil.bigDecimalToStr((CustomBigDecimal) PropertyUtils
                                    .getSimpleProperty(oriObj, name));
                        } else if (oriType == java.util.Date.class || oriType == java.sql.Date.class) {
                            strValue = CommonUtil.dateToString(((java.util.Date) PropertyUtils.getSimpleProperty(oriObj, name)),
                                    CommonUtil.OUTPUT_DATE_FORMAT);
                        } else if (oriType == Timestamp.class) {
                            Timestamp ts = (Timestamp) PropertyUtils.getSimpleProperty(oriObj, name);
                            if ((name.startsWith(SimpleConstants.CREATE_DATE_FIELD_NAME))
                                    || (name.startsWith(SimpleConstants.UPDATE_DATE_FIELD_NAME))) {
                                strValue = CommonUtil.timestampToString(ts);
                            } else {
                                strValue = CommonUtil.timestampToString(ts, CommonUtil.OUTPUT_DATETIME_FORMAT);
                            }
                        } else if (oriType == CustomSqlDate.class || oriType == CustomUtilDate.class) {
                            strValue = CommonUtil.dateToString(((java.util.Date) PropertyUtils.getSimpleProperty(oriObj, name)),
                                    CommonUtil.OUTPUT_DATE_FORMAT);
                        } else if (oriType == CustomTimestamp.class) {
                            CustomTimestamp ts = (CustomTimestamp) PropertyUtils.getSimpleProperty(oriObj, name);
                            strValue = CommonUtil.timestampToString(ts, CommonUtil.OUTPUT_DATETIME_FORMAT);
                        } else if (oriType.isPrimitive()) {
                            strValue = String.valueOf(PropertyUtils.getSimpleProperty(oriObj, name));
                        }
                        /*
                        if (Number.class.isAssignableFrom(oriType)) {
                            strValue = CommonUtil.getAppropriateNumberFormat(strValue);
                        }
                        */
                    }
                    PropertyDescriptor destPd = PropertyUtils.getPropertyDescriptor(destObj, name);
                    if (destPd != null && destPd.getWriteMethod() != null) {
                        PropertyUtils.setSimpleProperty(destObj, name, strValue);
                    }
                } catch (NoSuchMethodException e) {
                } catch (InvocationTargetException e) {
                    Exception te = CommonUtil.getTargetExecption(e);
                    Logger.logExceptions(oriObj, te);
                    throw new RuntimeException(te.getMessage());
                }
            }
        }
    }

    public static void copyByteArray(Object dest, Object orig) throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {

        if (dest == null)
            throw new IllegalArgumentException("No destination bean specified");
        if (orig == null)
            throw new IllegalArgumentException("No origin bean specified");
        PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(orig);
        for (int i = 0; i < origDescriptors.length; i++) {
            String name = origDescriptors[i].getName();
            Class oriType = PropertyUtils.getPropertyType(orig, name);
            try {
                if (PropertyUtils.getPropertyDescriptor(dest, name) != null) {
                    Class type = PropertyUtils.getPropertyType(dest, name);
                    // check if it is byte array or not
                    if (!oriType.getName().equals("[B"))
                        continue;
                    if (oriType != type)
                        continue;
                    if (PropertyUtils.getPropertyDescriptor(dest, name) == null || PropertyUtils.getPropertyDescriptor(dest, name).getWriteMethod() == null) continue;
                    if (PropertyUtils.getPropertyDescriptor(orig, name) == null || PropertyUtils.getPropertyDescriptor(orig, name).getReadMethod() == null) continue;
                    Object oriValue = PropertyUtils.getSimpleProperty(orig, name);
                    PropertyUtils.setSimpleProperty(dest, name, oriValue);
                }
            } catch (NoSuchMethodException e) {
                // Kind of ugly coding here
            } catch (Exception e) {
                Logger.logExceptions(e);
            }
        }
    }

    public static ChildList CopyChildList(ChildList child, Class childClass) {

        if (child == null || childClass == null) {
            return null;
        }
        ChildList newChild = new ChildList(childClass);
        for (int i = 0; i < child.size(); i++) {
            newChild.add(child.get(i));
        }
        return newChild;
    }

    /**
     * @ddeprecated
     * @param dest
     * @param destPrefix
     * @param orig
     * @param origPrefix
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     */
    public static void CpWithDiffPrefix(Object dest, String destPrefix, Object orig, String origPrefix)
            throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {

        if (dest == null)
            throw new IllegalArgumentException("No destination bean specified");
        if (orig == null)
            throw new IllegalArgumentException("No origin bean specified");
        destPrefix = CommonUtil.nullToString(destPrefix);
        origPrefix = CommonUtil.nullToString(origPrefix);
        PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(orig);
        for (int i = 0; i < origDescriptors.length; i++) {
            String origName = origDescriptors[i].getName();
            if (!origPrefix.equals("")) {
                if (!origName.startsWith(origPrefix)) {
                    continue;
                }
            }
            Class oriType = PropertyUtils.getPropertyType(orig, origName);
            String name = origName;
            String tempStr = "";
            if (!origPrefix.equals("")) {
                tempStr = name.substring(origPrefix.length(), origPrefix.length() + 1);
                name = name.substring(origPrefix.length() + 1);
                name = tempStr.toLowerCase() + name;
            }
            if (!destPrefix.equals("")) {
                tempStr = name.substring(0, 1);
                name = name.substring(origPrefix.length() + 1);
                name = destPrefix + tempStr.toUpperCase() + name;
            }
            try {
                if (PropertyUtils.getPropertyDescriptor(dest, name) != null) {
                    if (PropertyUtils.getPropertyDescriptor(dest, name) == null || PropertyUtils.getPropertyDescriptor(dest, name).getWriteMethod() == null) continue;
                    if (PropertyUtils.getPropertyDescriptor(orig, origName) == null || PropertyUtils.getPropertyDescriptor(orig, origName).getReadMethod() == null) continue;
                    Class type = PropertyUtils.getPropertyType(dest, name);
                    if (oriType == String.class) {
                        String value = (String) PropertyUtils.getSimpleProperty(orig, origName);
                        if (!type.isPrimitive()) {
                            if (type == Integer.class) {
                                Integer inValue = CommonUtil.strToInteger(value);
                                PropertyUtils.setProperty(dest, name, inValue);
                            } else if (type == BigDecimal.class) {
                                BigDecimal bd = CommonUtil.strToBigDecimal(value);
                                PropertyUtils.setSimpleProperty(dest, name, bd);
                            } else if (type == java.util.Date.class) {
                                java.util.Date inValue = CommonUtil.stringToDate(value);
                                PropertyUtils.setProperty(dest, name, inValue);
                            } else if (type == java.sql.Date.class) {
                                java.util.Date inValue = CommonUtil.stringToDate(value);
                                java.sql.Date dateValue = inValue == null ? null : new java.sql.Date(inValue.getTime());
                                PropertyUtils.setProperty(dest, name, dateValue);
                            } else if (type == java.sql.Timestamp.class) {
                                Timestamp inValue = CommonUtil.stringToTimestamp(value);
                                PropertyUtils.setProperty(dest, name, inValue);
                            } else if (type == BigInteger.class) {
                                BigInteger inValue = CommonUtil.strToBigInteger(value);
                                PropertyUtils.setProperty(dest, name, inValue);
                            } else if (type == String.class) {
                                // Poor Practice perhaps, setting everything to
                                // null;
                                if (value != null && value.trim().equals(""))
                                    value = null;
                                PropertyUtils.setSimpleProperty(dest, name, value);
                            }
                        } else {
                            if (type == int.class) {
                                Integer intValue = CommonUtil.strToInteger(value);
                                PropertyUtils.setProperty(dest, name, intValue);
                            }
                        }
                    } else if (oriType == type) {
                        Object oriValue = PropertyUtils.getSimpleProperty(orig, origName);
                        PropertyUtils.setSimpleProperty(dest, name, oriValue);
                    }
                }
            } catch (NoSuchMethodException e) {
                // Kind of ugly coding here
            } catch (Exception e) {
                Logger.logExceptions(e);
            }
        }
    }

    public static Object copy(Object orig) {
        Class clazz = orig.getClass();
        Object dest = null;

        try {
            dest = clazz.newInstance();
            PropertyUtils.copyProperties(dest, orig);
        } catch (InstantiationException e) {
            Logger.logExceptions(e);
        } catch (IllegalAccessException e) {
            Logger.logExceptions(e);
        } catch (InvocationTargetException e) {
            Logger.logExceptions(e);
        } catch (NoSuchMethodException e) {
            Logger.logExceptions(e);
        }

        return dest;
    }
}